/**
 * Classname: CopyByExtension
 * Version: 1.2
 * Date: 20-Aug-2007
 * * This is main class of command line program, that  copyies directory tree of
 *  <inputDir> to <outputDir>, but copies only the files with <ext> extension.
 * The program also preserves original creation dates of files copied.
 */

package il.co.entrypoint.app;

import org.apache.commons.io.DirectoryWalker;
import org.apache.commons.io.FileUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.io.File;
import java.io.IOException;


/**
 * <p>
 * This class can pass its inputDir recursivly with 'find()' method
 * and search for files with 'ext' extension.
 * Results of this search are stored in findResults attribute.
 * After that, the class can copy these files to output dir,
 * preserving its directory tree and creation date.
 * <p>
 * @author: grinfeld igor
 * @version: 1.2
 */

public class CopyByExtension extends DirectoryWalker {
    final static int WRONG_PARAMS =  -1;
    final static int IO_ERROR =  -2;

    /** source directory of files copied */
    protected String inputDir;

    /** destination directory to copy files */
    protected String outputDir;

    /** file with this extension will be copied from inputDir to outputDIr */
    protected String ext;

    /** results of walking at &lt; inputDir &gt; subtree */
    protected Collection<File> findResults;

    /**
     * Constructor of class
     * @param inputDir value for inputDir class propety
     * @param outputDir value for outputDir class propety
     * @param ext value for ext class propety
     * @throws IOException when inputDir is not directory or OutputDir is null 
     */
    public CopyByExtension(String inputDir,String outputDir,String ext) throws IOException {
        if(new File(inputDir).isDirectory())
            this.inputDir = inputDir;
        else
            throw new IOException();

         //if outputDir ends with '/' , this character must be deleted
         outputDir = new File(outputDir).getCanonicalPath();
         if (outputDir.length()>1 && outputDir.endsWith(File.separator)) {
             this.outputDir = outputDir.substring(0, (outputDir.length()-1) );
      }

      //if extension given with '.' at start, remove this character.
      if (this.ext  !=  null)  {
         ext = ext.toLowerCase();
          if(!ext.startsWith(".")) {
              this.ext="."+ext.toLowerCase();
          }
          else  {
              this.ext=ext.toLowerCase();
          }
      }
    }

    /**
     * method returns iterator of results of 'find' method
     * @return returns iterator for list of files
     * with 'ext' extension in 'inputDir'
     * */
    public Iterator<File> getResults() {
        if (findResults == null) {
            return null;
        }

        return findResults.iterator();
    }

    /**
     * method walks above input directory recursievly, and saves
     * every file with 'ext' extension to 'findResults' attribute
     * @throws IOException when inputDir is not a directory or doesn't exist
     */
    public void find() throws IOException {
      Collection<File> results = new ArrayList<File>();
        
      walk(new File(inputDir), results);
      findResults=results;
    }

    /**
     * method copies files from 'findResults' to output dir, preserving its
     * directory structure and creation date.
     * @throws IOException when outputDir is not a directory or doesn't exist
     */
    public void copy() throws IOException {
        Iterator<File> itr = findResults.iterator();
        File curFile;
        String curDestPath;

        while(itr != null && itr.hasNext())
        {
            curFile = itr.next();
            curDestPath = curFile.getCanonicalPath();

            //remove file:// and d:\ from source path
            int index = curDestPath.indexOf("://");
            if (index > 0) {
                curDestPath=curDestPath.substring(index+3);
            }

            //remove disk letter from windows-style path
            index = curDestPath.indexOf(":\\");
            if (index > 0) {
                curDestPath = curDestPath.substring(index+2);
            }

            index = curDestPath.indexOf(File.separator);
            if (index == 0) {
                curDestPath = curDestPath.substring(1);
            }

            curDestPath = outputDir + File.separator + curDestPath;
            FileUtils.copyFile(curFile, new File(curDestPath));
        }

    }

    /** method is inhereted from DirectoryWalker. Do nothing.
     *  @override:  org.apche.commons.io.DirectoryWalker.handleDirectory(File,Collection)
     * */
    protected boolean handleDirectory(
            File directory, int depth, Collection results) {
        return true;
    }

    /**
     * method is inhereted from DirectoryWalker.
     * it saves each file with 'ext' extension to 'findResults'
      *  @override:  org.apche.commons.io.DirectoryWalker.handleFile(File,Collection)
     */
    protected void handleFile(File file, int depth, Collection results) {
        //we work only with files
        if (file == null || !file.isFile()) {
            return;
        }

        //remove '.' at the start of last file extension, if exists
        String curName = file.getName().toLowerCase();        
        if (curName.endsWith(ext)) {
            results.add(file);
        }
    }

    public static void main( String[] args ) {
        //arguments number check
        if (args==null || args.length < 3) {
            //Message string that displayed before exit,
            // when wrong parameters have recieved
            String usageMsg =
                "\nUsage above : CopyByExtension &lt; inputDir &gt;  &lt; outputDir &gt;  &lt; ext &gt;\n" +
                "   Welcome to copy by extension utility.\n" +
                "This command line program copyies directory tree of  &gt; inputDir &lt; "+
                "to <outputDir>,\n" +
                "but copies only the files with &lt; ext &gt; extension.\n" +
                "The program also preserves original creation date of files copied";

            System.out.println(usageMsg);
            System.exit(WRONG_PARAMS);
        }

        //find all files with 'ext' extension in input directory
        //and copy these files to output directory
        try {
            CopyByExtension app = new CopyByExtension(args[0], args[1], args[2]);

            app.find();
            app.copy();

            //Print all copied files
            Iterator<File> itr = app.getResults();
            while (itr.hasNext()) {
                System.out.println((itr.next()).getName());
            }

        } catch(IOException e) {
            System.out.println("Error: error processing directory" + args[0]);
            System.exit(IO_ERROR);
        }
    }
}
